


module sdram_fifo(
	input				clk_50M,
	input				clk_100M,
	input				clk_9M,
	input				rst,
	
	//read
	input				read_req,
	output[15:0]		read_data,
	
	
	//write
	input					write_req,
	input[15:0]			write_data,
	
	
	
	
	//SDRAM
	output	wire		sdram_clk,
	output	wire		sdram_cke,
	output	wire		sdram_cs_n,
	output	wire		sdram_cas_n,
	output	wire		sdram_ras_n,
	output	wire		sdram_we_n,
	output	wire[1:0]	sdram_bank,
	output	wire[12:0]	sdram_addr,
	output	wire[1:0]	sdram_dqm,
	inout		[15:0]	sdram_dq,
	
	input			cmos_vsync,
	input			cmos_href,
	input[15:0]	mode
);







//--------------------------------------------------------------

//写
reg				sdram_write_req;
wire			sdram_write_valid;
wire[15:0]		sdram_write_data;
reg[12:0]		sdram_write_row;
reg[8:0]		sdram_write_col;
wire			sdram_write_ack;

//读
reg				sdram_read_req;
wire[15:0]		sdram_read_data;
reg[12:0]		sdram_read_row;
reg[8:0]		sdram_read_col;
wire			sdram_read_ack;
wire			sdram_read_valid;

reg[1:0]    w_bank;
reg[1:0]		r_bank;

reg[7:0]		wirte_size;





always@(posedge clk_100M or negedge rst)
begin
	if(rst == 1'b0)
	begin
		sdram_write_row <= 'd0;
		sdram_write_col <= 'd0;
		w_bank <= 'd0;

	end
	else if(cmos_vsync == 1'b1)
	begin
		sdram_write_row <= 'd0;
		sdram_write_col <= 'd0;
		if(w_bank == 2'b10)
			w_bank <= 'd0;
		else
			w_bank <= w_bank + 1'b1;
	
	end
	else if(cmos_href == 1'b0 && sdram_write_req == 1'b0 && wr_count < 'd2)
	begin
		sdram_write_col <= 'd0;
	end
	else if(sdram_write_ack == 1'b1)
	begin
	//	sdram_write_col <= sdram_write_col + wirte_size;
		if(sdram_write_col >= 'd470)
			begin
				sdram_write_col <= 'd0;
				if(sdram_write_row >= 'd271)
				begin
					sdram_write_row <= 'd0;
					w_bank <= w_bank + 1'b1;
					if(w_bank == 2'b10)
						w_bank <= 'd0;
					else
						w_bank <= w_bank + 1'b1;
			
				end
				else
					sdram_write_row <= sdram_write_row + 1'b1;
				
			end
		else begin
				sdram_write_col <= sdram_write_col + wirte_size;
				sdram_write_row <=  sdram_write_row;
		end
	end


end

sdram_top sdram_top_m0(

	.clk(clk_100M),
	.rst(rst),
	
	//SDRAM
	.sdram_clk(sdram_clk),
	.sdram_cke(sdram_cke),
	.sdram_cs_n(sdram_cs_n),
	.sdram_cas_n(sdram_cas_n),
	.sdram_ras_n(sdram_ras_n),
	.sdram_we_n(sdram_we_n),
	.sdram_bank(sdram_bank),
	.sdram_addr(sdram_addr),
	.sdram_dqm(sdram_dqm),
	.sdram_dq(sdram_dq),
	
	//写
	.write_req(sdram_write_req),
	.write_data_valid(sdram_write_valid),
	.write_data(sdram_write_data),
	.write_row(sdram_write_row),
	.write_col(sdram_write_col),
	.write_ack(sdram_write_ack),
	//读
	.read_req(sdram_read_req),
	.read_data(sdram_read_data),
	.read_row(sdram_read_row),
	.read_col(sdram_read_col),
	.read_ack(sdram_read_ack),
	.read_data_valid(sdram_read_valid),
	
	.w_bank(w_bank),
	.r_bank(r_bank),
	.wirte_size(wirte_size)
);

//写fifo，接收外部的数据，写入sdram ------------------------------------------------------

reg		r_en;
wire	r_empty;


reg		w_en;
wire  	w_full;

wire[8:0]	wr_count;    //写fifo中有的数据量


reg[5:0] write_test;

always@(posedge clk_50M or negedge rst)
begin
	if(rst == 1'b0)
		w_en <= 1'b0;
	else if(write_req == 1'b1 && w_full == 1'b0)
		w_en <= 1'b1;
	else
		w_en <= 1'b0;
end

always@(posedge clk_100M or negedge rst)
begin
	if(rst == 1'b0)
		wirte_size <= 'd0;
	else if(cmos_href == 1'b1)
		wirte_size <= 'd10;
	else if(wr_count >= 'd2)
		wirte_size <= wr_count;

end



always@(posedge clk_100M or negedge rst)
begin
	if(rst == 1'b0)
		write_test <= 'd0;
	else if(write_test >= 'd30)
		write_test <= write_test;
	else if(sdram_write_ack == 1'b1 && sdram_write_col >= 'd475 && sdram_write_row >= 'd271)
		write_test <= write_test + 1'b1;
	else
		write_test <= write_test;


end

always@(posedge clk_100M or negedge rst)
begin
	if(rst  == 1'b0)
		sdram_write_req <= 1'b0;
	else if(sdram_write_ack == 1'b1)// || write_test >= 'd30)
		sdram_write_req <= 1'b0;
	else if(wr_count >= wirte_size)
		sdram_write_req <= 1'b1;
	else if(wr_count <= wirte_size && sdram_write_req != 1'b1)
		sdram_write_req <= 1'b0;
	else
		sdram_write_req <= sdram_write_req;
end

always@(posedge clk_100M or negedge rst)
begin
	if(rst == 1'b0)
		r_en = 1'b0;
	else if(sdram_write_valid == 1'b1)
		r_en = 1'b1;
	else
		r_en = 1'b0;
end


FIFO w_fifo(
	
	.rst(rst),		
	
	//读
	.rclk(clk_100M), 					//读时钟    100MHz
	.r_en(r_en),					//读使能
	.r_data(sdram_write_data),		//读出的数据，写入sdram
	.r_empty(r_empty),				//是否为空
	
	
	//写
	.wclk(clk_50M),					//写时钟   50MHz
	.w_en(w_en),					//写使能
	.w_data(write_data),					//写入的数据
	.w_full(w_full),					//是否已经写满
	
	.data_count(wr_count)				//已经有的数据		
);

//读fifo，读取sdram中的内容，写入rfifo ------------------------------------------------------

reg 		r_read_en;
wire		r_read_empty;

reg			r_write_en;
wire			r_write_full;



reg[15:0]	r_write_data;	


wire[8:0]	r_data_count;  //读fifo中有的数据量




always@(posedge clk_100M or negedge rst)
begin
	if(rst == 1'b0)
		sdram_read_req <= 1'b0;
	else if(sdram_read_ack == 1'b1)
		sdram_read_req <= 1'b0;
	else if(r_data_count <= 'd400)
		sdram_read_req <= 1'b1;
	else
		sdram_read_req <= 1'b0;
end



//assign r_write_en = sdram_read_valid;

always@(posedge clk_9M or negedge rst)
begin
	if(rst == 1'b0)
		r_read_en <= 1'b0;
	else if(read_req == 1'b1)// && r_data_count > 'd100)
		r_read_en <= 1'b1;
	else if(r_data_count < 'd5 || read_req == 1'b0)
		r_read_en <= 1'b0;
	else
		r_read_en <= 1'b0;
end



always@(posedge clk_100M or negedge rst)
begin
	if(rst == 1'b0)
	begin
		sdram_read_row <= 'd0;
		sdram_read_col <= 'd0;
		r_bank <= 2'b10;
	end
	
	else if(sdram_read_ack == 1'b1)
	begin
		if(sdram_read_col >= 'd440)
			begin
				sdram_read_col <= 'd0;
				if(sdram_read_row >= 'd271)
				begin
					sdram_read_row<= 'd0;
					if(r_bank == 2'b10)
						r_bank <= 'd0;
					else
						r_bank <= r_bank + 1'b1;
					//r_bank <= r_bank + 1'b1;
				end
				else
					sdram_read_row <= sdram_read_row + 1'b1;
			end
		else begin
				sdram_read_col <= sdram_read_col + 'd40;
				sdram_read_row <=  sdram_read_row;
		end
	end

end

wire			gray_en;
wire			sobel_en;
wire			Erosion_en;

wire[15:0]	gray_data;
wire[15:0]	Sobel_data;
wire[15:0]  Erosion_data;


reg[7:0]		Sobel_thresh;
reg[7:0]		EE_flag;





always@(posedge clk_100M or negedge rst)
begin
	if(rst == 1'b0)
		r_write_en = 1'b0;
	else if(mode[15:8] ==  "1" || mode == 'd0)
		r_write_en = sdram_read_valid;
	else if(mode[15:8]  == "2")
		r_write_en = gray_en;
	else if(mode[15:8]  == "3")
	begin
		r_write_en   = sobel_en;
	end
	else if(mode[15:8]  == "4")
	begin
		r_write_en = Erosion_en;

	end
	else
	begin
		r_write_en = r_write_en;
	end
end

always@(posedge clk_100M or negedge rst)
begin
	if(rst == 1'b0)
	begin
		EE_flag  <= 'd0;
		Sobel_thresh <= 'd155;
	end
	else if(mode[15:8]  == "3")
		Sobel_thresh <= mode[7:0]; 
	else if(mode[15:8]  == "4")
		EE_flag <= mode[7:0];
	else
	begin
		Sobel_thresh <= Sobel_thresh;
		EE_flag <= EE_flag;
	end


end

always@(posedge clk_100M or negedge rst)
begin
	if(rst == 1'b0)
		r_write_data = 'd0;
	else if(mode[15:8] == "1" || mode == 'd0)
		r_write_data = sdram_read_data;
	else if(mode[15:8] == "2")
		r_write_data = gray_data;
	else if(mode[15:8] == "3")
		r_write_data = Sobel_data;
	else if(mode[15:8] == "4")
		r_write_data = Erosion_data;
	else
		r_write_data = r_write_data;

end



FIFO r_fifo(
	
	.rst(rst),		
	
	//读
	.rclk(clk_9M), 					//读时钟    10MHz
	.r_en(r_read_en),					//读使能
	.r_data(read_data),		//读出的数据
	.r_empty(r_read_empty),				//是否为空
	
	//写  读取sdram中的内容，写入rfifo
	.wclk(clk_100M),					//写时钟   100MHz
	.w_en(r_write_en),					//写使能
	.w_data(r_write_data),			//写入的数据
	.w_full(r_write_full),				//是否已经写满

	.data_count(r_data_count)			//已经有的数据		
);




//通过取平均值来获取灰度值
RGB565_2_GRAY RGB565_2_GRAY_V(

	.clk(clk_100M),
	.rst(rst),
	
	
	.data_en(sdram_read_valid),				//sdram读取数据有效
	.write_en(gray_en),			//写入fifo有效
	
	
	.data_in(sdram_read_data),				//sdram读取到的数据
	.data_out(gray_data)				//转为灰度输出
);


Sobel_detection Sobel_detection_V1(

		.clk(clk_100M),
		.rst(rst),
		
		
		
		.data_en(gray_en),
		.write_en(sobel_en),
			
		.Sobel_thresh(Sobel_thresh),
		
		.data_in(gray_data[7:0]),
		.sobel_out(Sobel_data)
);

Erosion_or_Erode Erosion_or_Erode_V1(

		.clk(clk_100M),
		.rst(rst),
		
		.data_en(sobel_en),
		.write_en(Erosion_en),
			
			
		.flag(EE_flag),
		
		
		.data_in(Sobel_data[7:0]),
		.erosion_out(Erosion_data)
);

endmodule 